//
//  GenericDownloader.m
//  Catalogo
//
//  Created by UJI on 22/05/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "GenericDownloader.h"


@implementation GenericDownloader

@synthesize downloadDelegate;
@synthesize downloadItems;
@synthesize numRetries;
@synthesize allowFinishWithErrors;

- (void) dealloc{
    [downloadDelegate release];
    [queue release];
    [retriesHash release];
    
    [super dealloc];
}

- (id) init{
	if ([super init]!=nil){
        queue = [[NSOperationQueue alloc] init];
        [queue setMaxConcurrentOperationCount:5];
        fileManager = [NSFileManager defaultManager];
        retriesHash = [[NSMutableDictionary alloc] init];
        numRetries = 0;
        numDownloadErrors = 0;

        //Por defecto si se produce un error se termina la descarga
        allowFinishWithErrors = NO;
        
        useAccurateProgress = NO;
	}
	
	return self;
}


- (void) startDownload{
    stopped = NO;
    
    if (useAccurateProgress){
        totalDownload = 0;
        [self calculateTotalSize];   
        
        if (totalSize != -1){
            [self.downloadDelegate genericDownloaderProgressStarted: totalSize];
        }

    }
    
    numDownloads = [downloadItems count];
    numDownloadedFiles = 0;
    [retriesHash removeAllObjects];
    
    errorSent = NO;
    
    [self.downloadDelegate genericDownloaderStarted: [downloadItems count]];
    
    if ([downloadItems count] == 0){
        [self.downloadDelegate genericDownloaderFinished];
    }
    else{
        for (GenericDownloadItem * downloadItem in downloadItems) {
            [self startDownloadItem: downloadItem];
        }
    }
}

- (void) calculateTotalSize{
    totalSize = 0;
    for (GenericDownloadItem * downloadItem in downloadItems) {
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:downloadItem.downloadPath] cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:5.0];
        [request setHTTPMethod:@"HEAD"];
        
        NSURLResponse *response = [[NSURLResponse alloc] init];
        NSError *error = [[NSError alloc] init];
        
        [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
        long dataLength = [response expectedContentLength];
        
        if (dataLength != NSURLResponseUnknownLength){
            totalSize += dataLength;
        }
        else{
            totalSize = -1;
        }
    }

}

- (void) stopDownload{
    //Procedo a la cancelación de todas las operaciones
    [queue cancelAllOperations];
    
    stopped = YES;
    
    [self.downloadDelegate genericDownloaderStopped];
}


- (void) startDownloadItem: (GenericDownloadItem *) downloadItem{
    NSMutableDictionary * params = [[NSMutableDictionary alloc] initWithObjects: 
                                     [NSArray arrayWithObjects: downloadItem,nil] 
                                                                         forKeys: [NSArray arrayWithObjects:@"DOWNLOAD_ITEM",nil]] ; 
    
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] 
                                        initWithTarget:self
                                        selector:@selector(doDownloadFileAsync:) 
                                        object:params];
    
    [queue addOperation:operation]; 
    [operation release];
    [params release];
}

- (void) doDownloadFileAsync: (id)sender{
    if (stopped){
        return;  
    }
	NSDictionary * params = (NSDictionary *)sender;
	GenericDownloadItem * downloadItem = [params objectForKey:@"DOWNLOAD_ITEM"];
    
    //NSLog(@"Empezando a descargar %@", downloadItem.downloadPath);
    
    NSURL * aUrl = [NSURL URLWithString:downloadItem.downloadPath];
	NSData * data = [NSData dataWithContentsOfURL:aUrl];
    //NSLog(@"Descargado %@", downloadItem.downloadPath);
    
	if (data == nil){
        if (stopped){
            return;  
        }
        
        [self onDownloadItemError: downloadItem];
    }
    else{
        if ([data writeToFile: downloadItem.cachePath atomically:NO]){
            if (stopped){
                return;  
            }
            
            //[NSThread sleepForTimeInterval: arc4random() % 10];
            
            //Reducimos en uno las descargas
            numDownloadedFiles++;
                      
            if (useAccurateProgress && totalSize != -1){
                [self.downloadDelegate genericDownloaderProgressChanged: totalDownload totalSize: totalSize];
            }
            
            //Comunicamos el cambio
            [self.downloadDelegate genericDownloaderProcessChanged: numDownloadedFiles];
            //Y luego el item que se ha descargado
            [self.downloadDelegate genericDownloaderItemDownloadSuccess: downloadItem];
            
            if (numDownloadedFiles == numDownloads){
                [self.downloadDelegate genericDownloaderFinished];
            }
            else{
                if (allowFinishWithErrors && ((numDownloadedFiles + numDownloadErrors) == numDownloads) && !errorSent){
                    errorSent = YES;
                    [self.downloadDelegate genericDownloaderFinishedWithNumErrors:numDownloadErrors andNumItemsDownloaded:numDownloadedFiles];
                }
            }
        }
        else{
            //Revisar si esto no debería estar descomentado (estoy torraooo)
            //[self.downloadDelegate genericDownloaderItemDownloadError: downloadItem];
            [self onDownloadItemError: downloadItem];
        }
    }
 
}

- (void) onDownloadItemError: (GenericDownloadItem *) downloadItem{
    if (numRetries == 0){
        [self.downloadDelegate genericDownloaderItemDownloadError: downloadItem];
        
        if (!allowFinishWithErrors && !errorSent){
            errorSent = YES;
            [self.downloadDelegate genericDownloaderError: NSLocalizedString(@"Error al descargar un recurso",nil)];            
        }
        else{
            numDownloadErrors++;
        }
        return;
    }
    
    NSNumber * errorsDownloadItem = [retriesHash objectForKey: [downloadItem downloadPath]];
    //Si no había se inicia de nuevo la descarga y el retriesHash se pone a 1
    if (errorsDownloadItem == nil){
        [retriesHash setObject:[NSNumber numberWithInt:1] forKey: [downloadItem downloadPath]];
        [self startDownloadItem: downloadItem];
    }
    else if ([errorsDownloadItem intValue] < numRetries) {
        [retriesHash setObject:[NSNumber numberWithInt: ([errorsDownloadItem intValue] +1 )] forKey: [downloadItem downloadPath]];
        [self startDownloadItem: downloadItem];
    }
    else{
        [self.downloadDelegate genericDownloaderItemDownloadError: downloadItem];
        
        if (!allowFinishWithErrors && !errorSent){
            errorSent = YES;
            [self.downloadDelegate genericDownloaderError: NSLocalizedString(@"Error al descargar un recurso",nil)];  
        }
        else{
            numDownloadErrors++;
        }

    }
    
}


@end